import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from client_ui import *
from client_model import *
from protocol_mqtt import *
from protocol_multimedia import *
from device_multimedia import *
import time
import logging
import threading
import numpy as np
logging.basicConfig(level=logging.DEBUG)


class MainWindow(MainUi):
    login_ack_signal = pyqtSignal(str, str)
    chat_ack_signal = pyqtSignal(dict)
    video_update_signal = pyqtSignal(bytes)
    message_rec_signal = pyqtSignal(dict)
    system_message = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.mqttc = MainMQTT()
        self.mmc = MultiMediaClient(self.mqttc)
        self.mms = MultiMediaServer(self.mqttc)
        self.ac = AudioClient()
        self.vc = VideoClient()
        self.bindEvents()
        self.bindCallbacks()
        self.user_list_model = UserListModel(self)
        self.chat_list_model = ChatListModel(self)
        self.chatSideBar.chatlistview.setModel(self.chat_list_model)
        self.contactsSidebar.userlistView.setModel(self.user_list_model)
        self.chattinguser = None
        self.quiting = False

    def bindEvents(self):
        ### 连接 ###
        self.connectSidebar.connectButton.clicked.connect(
            self.on_connect_button_clicked)
        ### 登录 ###
        self.loginSidebar.loginButton.clicked.connect(
            self.on_login_button_clicked)
        self.loginSidebar.registerButton.clicked.connect(
            self.on_start_register_button_clicked)
        ### 注册 ###
        self.registerSidebar.registerButton.clicked.connect(
            self.on_register_button_clicked)
        self.registerSidebar.returnButton.clicked.connect(
            self.on_return_login_button_clicked)
        ### 用户列表 ###
        self.contactsSidebar.userlistView.pressed.connect(
            self.on_selected_user_changed)
        self.contactsSidebar.chatAction.triggered.connect(self.on_chat_action)
        self.contactsSidebar.userlistView.doubleClicked.connect(
            self.on_chat_action)
        self.contactsSidebar.addfAction.triggered.connect(self.on_addf_action)
        self.contactsSidebar.refreshAction.triggered.connect(
            self.on_refresh_action)
        ### 聊天列表 ###
        self.chatSideBar.chatlistview.clicked.connect(self.on_chat_changed)
        ### 聊天窗 ###
        self.chatBox.audioAction.triggered.connect(self.on_audio_action)
        self.chatBox.videoAction.triggered.connect(self.on_video_action)
        self.chatBox.fileAction.triggered.connect(self.on_file_action)
        self.chatBox.sendAction.triggered.connect(self.on_send_action)
        self.chatBox.sendBox.textChanged.connect(self.on_sendbox_textchanged)
        self.chatBox.receiveBox.cursorPositionChanged.connect(self.auto_scroll)
        ### 窗口控制 ###
        self.rightSideCtrlBtn.clicked.connect(self.on_rightSideCtrlBtn_clicked)
        ### 信号 ###
        self.login_ack_signal.connect(self.login_ack)
        self.chat_ack_signal.connect(self.chat_ack)
        self.video_update_signal.connect(self.video_update)
        self.message_rec_signal.connect(self.message_rec)
        self.system_message.connect(self.sys_msg)

    def bindCallbacks(self):

        self.mqttc.login_ack = self.login_ack_signal.emit
        self.mqttc.login_rej = self.login_rej
        self.mqttc.register_ack = self.register_ack
        self.mqttc.register_rej = self.register_rej
        self.mqttc.onlinelist_update = self.onlinelist_update
        self.mqttc.friendlist_update = self.friendlist_update
        self.mqttc.addf_ack = self.addf_ack
        self.mqttc.addf_rej = self.addf_rej
        self.mqttc.addfriend_to = self.addfriend_to
        self.mqttc.chat_ack = self.chat_ack_signal.emit
        self.mqttc.chat_rej = self.chat_rej
        self.mqttc.message_rec = self.message_rec_signal.emit
        self.mqttc.usermessage_rec = self.usermessage_rec

        self.mmc.audio_ack = self.audio_ack
        self.mmc.audio_play = self.ac.play_frame
        self.mmc.video_ack = self.video_ack
        self.mmc.video_play = self.video_update_signal.emit
        self.mmc.file_send = self.file_send
        self.mms.file_req = self.file_req
        self.mms.file_rec = self.file_rec

    #########################################
    ###                事件                ###
    #########################################

    ### 连接 ###
    def on_connect_button_clicked(self):
        # update ui
        self.connectSidebar.connecting()
        QApplication.processEvents()
        # connect server
        addr, port = self.connectSidebar.get_addr()
        # try:
        res = self.mqttc.connect_server(addr, port)
        if res == 0:
            # update ui
            self.connectSidebar.connected()
            self.connectSidebar.setHidden(True)
            self.loginSidebar.setHidden(False)
            self.loginSidebar.idLineEdit.setFocus(True)
        else:
            raise ValueError
        # except:
            # update ui
            # self.connectSidebar.connection_fail()

    ### 登录 ###
    def on_login_button_clicked(self):
        # update ui
        self.loginSidebar.loggingin()
        # login
        self.mqttc.login(self.loginSidebar.idLineEdit.text(),
                         self.loginSidebar.pwdLineEdit.text())

    def on_start_register_button_clicked(self):
        # update ui
        self.loginSidebar.setHidden(True)
        self.registerSidebar.setHidden(False)

    ### 注册 ###
    def on_register_button_clicked(self):
        # update ui
        self.registerSidebar.registing()
        # register
        self.mqttc.register(self.registerSidebar.idLineEdit.text(),
                            self.registerSidebar.pwdLineEdit.text())

    def on_return_login_button_clicked(self):
        # update ui
        self.loginSidebar.setHidden(False)
        self.registerSidebar.setHidden(True)

    ### 用户列表 ###
    def on_selected_user_changed(self, index):
        # self.connectSidebar.listView
        self.userlist_selected_user = self.user_list_model.data(
            index, raw=True).user_id

    def on_chat_action(self):
        self.chat_list_selected_user = self.userlist_selected_user
        self.mqttc.chat(self.userlist_selected_user)

    def on_addf_action(self):
        self.mqttc.addfriend(self.userlist_selected_user)

    def on_refresh_action(self):
        self.mqttc.getuserlist()

    ### 聊天列表 ###

    def on_chat_changed(self, index):
        self.chat_list_selected_user = self.chat_list_model.data(
            index, raw=True).user_id
        self.chatbox_refresh(self.chat_list_selected_user)

    ### 聊天窗 ###
    def on_audio_action(self):
        if not self.mmc.audio_using:
            self.mmc.audio_on(self.chattinguser.user_id,
                              self.chattinguser.user_session, 'audio')
            self.mmc.audio_using = True
            self.ac.play()
        else:
            self.mmc.audio_using = False
            self.mmc.audio_off()
            self.mmc.audio_using = False
            self.ac.stop()

    def on_video_action(self):
        if not self.mmc.video_using:
            self.mmc.video_using = True
            self.mmc.video_on(self.chattinguser.user_id,
                              self.chattinguser.user_session, 'video')
        else:
            self.chatBox.videoLabel.setHidden(True)
            self.chatBox.receiveBox.setHidden(False)
            self.mmc.video_using = False
            self.mmc.video_off()

    def on_file_action(self):
        fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')
        self.filename = fname[0]
        self.mmc.file_req(self.chattinguser.user_id,
                          self.chattinguser.user_session, self.filename.split("/")[-1])
        self.system_message.emit("文件请求已发送 " + self.filename)

    def on_send_action(self):
        if self.chattinguser:
            self.mqttc.send_message(
                self.chattinguser.user_id, self.chattinguser.user_session, self.chatBox.sendBox.toPlainText())
            self.chat_list_model.beginResetModel()
            self.chat_list_model.updateSendMessage(
                self.chattinguser.user_id, "")
            self.chat_list_model.updateRecMessage(
                self.chattinguser.user_id, self.chatBox.sendBox.toPlainText())
            self.chatbox_refresh(self.chattinguser.user_id)
            self.chat_list_model.endResetModel()

    def on_sendbox_textchanged(self):
        self.chat_list_model.beginResetModel()
        self.chat_list_model.updateSendMessage(self.chattinguser.user_id,
                                               self.chatBox.sendBox.toPlainText())
        self.chat_list_model.endResetModel()

    def auto_scroll(self):
        cursor = self.chatBox.receiveBox.textCursor()
        cursor.movePosition(QTextCursor.End)
        self.chatBox.receiveBox.setTextCursor(cursor)
    ### 窗口控制 ###

    def on_rightSideCtrlBtn_clicked(self):
        tmp = self.contactsSidebar.isVisible()
        if tmp:
            self.rightSideCtrlBtn.setText("<")
        else:
            self.rightSideCtrlBtn.setText(">")

        self.contactsSidebar.setHidden(tmp)

    ### 信号 ###
    def login_ack(self, user_id, session):
        self.rightSideCtrlBtn.setEnabled(True)
        self.rightSideCtrlBtn.setText(">")
        self.emptyMain.setHidden(True)
        self.chatBox.setHidden(False)
        self.loginSidebar.loggedin()
        self.loginSidebar.setHidden(True)
        self.contactsSidebar.setHidden(False)
        self.start_userlist_loop()

    def chat_ack(self, chat_list):
        self.chat_list_model.beginResetModel()
        for u in list(chat_list.keys()):
            if chat_list[u] != {}:
                self.chat_list_model.addChat(
                    [u, self.user_list_model.getNameFromId(u), chat_list[u]])
                self.chatbox_refresh(u)
        self.chat_list_model.endResetModel()

    def chatbox_refresh(self, user_id):
        self.chattinguser = self.chat_list_model.getDataFromId(user_id)
        self.chatBox.receiveBox.setText(self.chattinguser.rec_text)
        self.chatBox.sendBox.setText(self.chattinguser.send_text)

    def video_update(self, data):
        data = self.vc.play_frame(data)
        img = QImage(data, 640, 480, QImage.Format_RGB888).rgbSwapped()
        qpixmap = QPixmap.fromImage(img)
        self.chatBox.videoLabel.setPixmap(qpixmap)
        self.chatBox.videoLabel.setHidden(False)
        self.chatBox.receiveBox.setHidden(True)

    def closeEvent(self, event):
        reply = QMessageBox.question(self, 'Message',
                                     "Are you sure to quit?", QMessageBox.Yes |
                                     QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            self.quiting = True
            try:
                self.update_userlist_t.cancel()
                self.mmc.audio_using = False
                self.mmc.audio_off()
                self.mmc.audio_using = False
                self.ac.stop()
                self.mmc.video_using = False
                self.mmc.video_off()
            except:
                pass
            event.accept()
        else:
            event.ignore()

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Return:
            self.chatBox.sendBox.setText(
                self.chatBox.sendBox.toPlainText()[:-1])
            self.on_send_action()

    #########################################
    ###                回调                ###
    #########################################

    ### 登录 ###
    def login_rej(self):
        self.loginSidebar.login_fail()

    ### 注册 ###
    def register_ack(self, user_id):
        self.registerSidebar.registed()
        self.loginSidebar.registed(user_id)
        self.registerSidebar.setHidden(True)
        self.loginSidebar.setHidden(False)

    def register_rej(self):
        self.registerSidebar.register_fail()

    ### 用户更新 ###
    def onlinelist_update(self, onlinelist):
        # update user list
        self.user_list_model.beginMoveRows
        self.user_list_model.setUserListFromId(onlinelist)
        self.user_list_model.endResetModel()
        self.mqttc.getfriendlist()

    def friendlist_update(self, friendlist):
        self.user_list_model.beginResetModel()
        self.user_list_model.resetFriend()
        for u in list(friendlist.keys()):
            self.user_list_model.addFriend(u, friendlist[u])
        self.user_list_model.endResetModel()

    ### 添加好友 ###
    def addf_ack(self):
        self.contactsSidebar.setInfo("好友请求成功")
        self.on_refresh_action()

    def addf_rej(self):
        self.contactsSidebar.infoBar.setText("好友请求失败")

    ### 好友请求 ###
    def addfriend_to(self, request_user):
        self.contactsSidebar.infoBar.setText(
            "好友请求:%s(%s)" % (request_user[1], request_user[0]))
        self.on_refresh_action()

    ### 聊天请求 ###
    def chat_rej(self):
        QMessageBox.question(self, 'Chat rejected!',
                             "Something wrong with server or network.",
                             QMessageBox.Ok, QMessageBox.Ok)

    def message_rec(self, data):
        u = data['user_id']
        self.chat_list_model.beginResetModel()
        self.chat_list_model.addChat(
            [u, self.user_list_model.getNameFromId(u), data['session'], data['message']])
        self.chat_list_model.updateRecMessage(
            u, data['message'], user_name=self.user_list_model.getNameFromId(u))
        self.chat_list_model.beginResetModel()
        self.chatbox_refresh(u)

    def sys_msg(self, message):
        self.chat_list_model.beginResetModel()
        self.chat_list_model.updateSendMessage(
            self.chattinguser.user_id, "")
        self.chat_list_model.updateRecMessage(
            self.chattinguser.user_id, message, user_name='系统消息')
        self.chatbox_refresh(self.chattinguser.user_id)
        self.chat_list_model.endResetModel()

    def usermessage_rec(self, message):
        if self.mmc.on_message(message):
            pass
        elif self.mms.on_message(message):
            pass

    def audio_ack(self):
        self.mmc.audio_on()
        logging.debug("audio ack received")

    def video_ack(self):
        self.mmc.video_on()
        logging.debug("video ack received")

    def file_send(self, data):
        topic = "/" + data['user_id'] + "/" + \
            data['session'] + "/" + data['topic']
        with open(self.filename, 'rb') as f:
            payload = f.read()
        if len(payload) / 1024 / 1024 > 128:
            self.system_message.emit("文件太大了")
            print('too big')
        else:
            self.system_message.emit("已发送文件 " + self.filename)
            t = threading.Timer(0, self.mqttc.publish,
                                args=(topic, payload, 2))
            t.start()

    def file_req(self, user_id, session):
        self.chat_ack_signal.emit({user_id: session})
        self.system_message.emit('收到文件请求 ' + self.mms.filename)
        self.mms.file_ack('file')

    def file_rec(self, data, filename):
        with open(filename, 'wb') as f:
            f.write(data)
            self.system_message.emit("文件已写入 " + filename)
    #########################################
    ###                函数                ###
    #########################################

    ### 定时更新用户列表 ###
    def start_userlist_loop(self):
        self.mqttc.ping()
        if not self.quiting:
            self.update_userlist_t = threading.Timer(
                60, self.start_userlist_loop)
            self.update_userlist_t.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())
